home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / file-tra / fsp-2.7 / fsp-2 / fsp / server / lib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-21  |  8.8 KB  |  329 lines

  1.     /*********************************************************************\
  2.     *  Copyright (c) 1991 by Wen-King Su (wen-king@vlsi.cs.caltech.edu)   *
  3.     *                                                                     *
  4.     *  You may copy or modify this file in any manner you wish, provided  *
  5.     *  that this notice is always included, and that you hold the author  *
  6.     *  harmless for any loss or damage resulting from the installation or *
  7.     *  use of this software.                                              *
  8.     \*********************************************************************/
  9.  
  10. #include "tweak.h"
  11. #include "server_def.h"
  12. #include "s_extern.h"
  13. #include "co_extern.h"
  14.  
  15. extern int errno;
  16.  
  17. #ifdef VMS  
  18. #define malloc VAXC$MALLOC_OPT
  19. #define free VAXC$FREE_OPT
  20. extern int isvar; /* in server_file.c */
  21. #endif
  22.  
  23. extern int no_unnamed;
  24.  
  25. static int myport = 0;
  26. static int myfd;
  27. static int interrupted = 0;
  28. static int thc[THCCOUNT];
  29. static time_t thcbase;
  30.  
  31. extern int priv_mode;
  32. extern unsigned int maxthcallowed;
  33.  
  34. static void server_interrupt PROTO1(int, signum)
  35. {
  36.   interrupted = 1;
  37. #ifndef RELIABLE_SIGNALS
  38.   signal(SIGALRM,server_interrupt);
  39. #endif
  40. }
  41.  
  42. /****************************************************************************
  43.  *  This is the message filter.  It is called by main with a timeout value.
  44.  *  If timeout is -1, it will never time out.  Otherwise, it waits for a
  45.  *  message.  If timed out, it returns.  Otherwise it pass it through checks.
  46.  *  Those message that passed get sent to the dispatch loop.
  47.  ****************************************************************************/
  48.  
  49. int server_loop PROTO1(unsigned long, timeout)
  50. {
  51.   unsigned long cur_time;
  52.   HTAB *hp;
  53.   char *ir;
  54.   UBUF rbuf;
  55.   struct sockaddr_in from;
  56.   unsigned int u, sum, mask, rlen, rkey;
  57.   int retval, bytes, old;
  58.   unsigned char *s, *d, *t;
  59.   
  60.   while(1) {
  61.     mask = 1 << myfd;
  62.     if(interrupted) {
  63.       dump_htab();
  64.       dump_iptab();
  65.       interrupted = 0;
  66.     }
  67.     retval = _x_select(&mask, timeout);
  68.       
  69.     if(retval == -1) {
  70.       if(errno == EINTR) continue;
  71.       perror("select");
  72.       exit(1);
  73.     }
  74.       
  75.     if(retval == 1) {   /* an incoming message is waiting */
  76.       bytes = sizeof(from);
  77.       if((bytes = recvfrom(myfd,(char*)&rbuf,sizeof(rbuf),0,
  78.                (struct sockaddr *)&from, &bytes)) < UBUF_HSIZE)
  79.     continue;
  80.       
  81.       rlen = BB_READ2(rbuf.bb_len);
  82.       if((int) (rlen+UBUF_HSIZE) > bytes) continue;    /* truncated.  */
  83.       
  84.       if(!(ir = check_ip(from.sin_addr.s_addr)))
  85.     ir = priv_mode ? "DFSP service not available": "N";
  86.       
  87.       switch (*ir) {
  88.         case 'D':    /* disabled host - return error message */
  89.       if (rbuf.cmd == CC_BYE)
  90.         break;
  91.       send_error(&from,&rbuf,&ir[1]);
  92.       continue;
  93.     case 'I':    /* ignore the host */
  94.       continue;
  95.     case 'N':    /* normal host */
  96.       break;
  97.     default:
  98.       fputs("check_ip() returned illegal host type\n",stderr);
  99.       exit(0);
  100.       }
  101.       
  102.       if(!(hp = find_host(from.sin_addr.s_addr))) {
  103.     fputs("find host failed\n",stderr);
  104.     exit(0);
  105.       }
  106.       
  107.       if(hp->hostname == 0 && no_unnamed) {
  108.     send_error(&from,&rbuf, REVERSE_ERR_MSG);
  109.     continue;
  110.       }
  111.       
  112.       old = 0;
  113.       cur_time = time((time_t *) 0);
  114.       
  115.       rkey = BB_READ2(rbuf.bb_key);
  116.       if(hp->next_key != rkey) {
  117.     if(!hp->active)
  118.       hp->last_key = hp->next_key = rkey;
  119.     else {
  120.       if(hp->last_key == rkey) {
  121.         if(cur_time < hp->last_acc + 3) continue;
  122.         old = 1;
  123.       } else {
  124.         if(cur_time < hp->last_acc + 60) continue;
  125.       }
  126.     }
  127.       }
  128.       
  129.       hp->active = 1;
  130.       hp->last_acc = cur_time;
  131.       
  132.       s = (unsigned char *) &rbuf;
  133.       d = s + bytes;
  134.       u = rbuf.sum; rbuf.sum = 0;
  135.       for(t = s, sum = bytes; t < d; sum += *t++);
  136.       sum = (sum + (sum >> 8)) & 0xff;
  137.       if(sum != u) continue;            /* wrong check sum */
  138.       
  139.       server_get_packet(bytes,&rbuf,old,hp,&from);
  140.     } else return(0);                /* got a timeout */
  141.   }
  142. }
  143.  
  144. /****************************************************************************
  145.  * Routine to return a 16-bit key with random number in the first 8-bits and
  146.  * zero in the second 8-bits.
  147.  ****************************************************************************/
  148.  
  149. unsigned long get_next_key PROTO0((void))
  150. {
  151.   unsigned long k;
  152.   
  153.   k = random();
  154.   k = k ^ (k >> 8) ^ (k >> 16) ^ (k << 8);
  155.   
  156.   return(k & 0xff00);
  157. }
  158.  
  159. /****************************************************************************
  160.  * Generic routine for sending reply back to clients.
  161.  *        from: client address structure.
  162.  *          ub: pointer to the message buffer.
  163.  *  len1, len2: lengths of the two data regions in the message buffer.
  164.  ****************************************************************************/
  165.  
  166. int server_reply PROTO4(struct sockaddr_in *, from, UBUF *, ub,
  167.             int, len1,int, len2)
  168. {
  169.   unsigned char *s, *t, *d;
  170.   unsigned sum;
  171.   time_t thcclock;
  172.   int i, thcsum;
  173.   
  174.   if(dbug) fprintf(stderr,"snd (%c,%d,%d,%lu) ---> %d.%d.%d.%d\n",
  175.            ub->cmd, len1, len2, BB_READ4(ub->bb_pos),
  176.            ((unsigned char *)(&(from->sin_addr.s_addr)))[0],
  177.            ((unsigned char *)(&(from->sin_addr.s_addr)))[1],
  178.            ((unsigned char *)(&(from->sin_addr.s_addr)))[2],
  179.            ((unsigned char *)(&(from->sin_addr.s_addr)))[3]);
  180.   
  181.   BB_WRITE2(ub->bb_len,len1);
  182.   
  183.   ub->sum = 0;
  184.   s = (unsigned char *) ub;
  185.   d = s + (len1 + len2 + UBUF_HSIZE);
  186.   for(t = s, sum = 0; t < d; sum += *t++);
  187.   ub->sum = sum + (sum >> 8);
  188.   
  189.   /*
  190.    * Check that we do not exceed maximum throughput allowed before sending
  191.    */
  192.   if(maxthcallowed)
  193.     for(;;) {
  194.       time(&thcclock);
  195.       if(thcclock > thcbase) {
  196.     if(thcclock>thcbase+THCCOUNT) {
  197.       int i;
  198.       for(i = 0; i < THCCOUNT; thc[i++]=0);
  199.       thcbase = thcclock;
  200.     } else {
  201.       while (thcclock > thcbase) {
  202.         for(i = THCCOUNT-1; i>0; i--) thc[i] = thc[i-1];
  203.         thc[0] = 0;
  204.         thcbase++;
  205.       }
  206.     }
  207.       }
  208.       for(i = 0, thcsum = 0; i< THCCOUNT; thcsum+= thc[i++]);
  209.       thcsum /= THCCOUNT;
  210.       if(dbug)
  211. {
  212.     fprintf(stderr, "Average throughput: %d bytes/s | ", thcsum);
  213. for (i= THCCOUNT-1;i>=0;i--) fprintf(stderr,"%5d ",thc[i]) ;
  214. fprintf(stderr,"\n") ;
  215. }
  216.       if(thcsum <= maxthcallowed) {
  217.     thc[0]+=(len1+len2+UBUF_HSIZE);
  218.     break;
  219.       }
  220.       if(dbug) fprintf(stderr, "Throughput too high, waiting.\n");
  221.       sleep(1);
  222.     }
  223.   
  224.   if(sendto(myfd,(char *)ub,(len1 + len2 + UBUF_HSIZE),0,
  225.         (struct sockaddr *)from,sizeof(struct sockaddr_in)) == -1) {
  226.     perror("sendto");
  227.     exit(1);
  228.   }
  229. }
  230.  
  231. /****************************************************************************
  232.  * Send an error string.
  233.  ****************************************************************************/
  234.  
  235. int send_error PROTO3(struct sockaddr_in *, from, UBUF *, ub, char *, msg)
  236. {
  237.   char *d;
  238.   
  239.   for(d = ub->buf; *d++ = *msg++; );
  240.   ub->cmd = CC_ERR;
  241.   
  242.   server_reply(from,ub,d-ub->buf,0);
  243. }
  244.  
  245. /****************************************************************************
  246.  * Send a block of data read from the file 'fp'.  Offset information is
  247.  * contained in the input ub message buffer, which also doubles as the output
  248.  * message buffer.
  249.  ****************************************************************************/
  250.  
  251. void send_file PROTO5(struct sockaddr_in *, from, UBUF *, ub, FILE *, fp,
  252.               int, has_len, char *, lp)
  253. {
  254.   int bytes, len;
  255.   unsigned long pos;
  256. #ifdef VMS
  257.   char *buf;  /* temp buffer for seek on var.rec.format files */
  258.   register int rtime = 5; /* max number of fread retries (var.rec.) */
  259. #endif
  260.   
  261.   if(has_len == 2) {    /* recover length field if it exists */
  262.     len  = (len=lp[0] << 8) + lp[1];
  263.     if(len > UBUF_SPACE || len < 0) len = UBUF_SPACE;
  264.   } else len  = UBUF_SPACE; /* use default if it doesn't exist */
  265.  
  266.   pos = BB_READ4(ub->bb_pos);
  267.   
  268. #ifdef VMS
  269.   if(isvar) {
  270.     /* fseek fails on files in variable record format */
  271.     rewind(fp);
  272.     buf=(char *)malloc(pos);
  273.     bytes = fread(buf,1, pos, fp); /* dummy read pos bytes */
  274.     free(buf);
  275.   } else
  276.     if(pos != ftell(fp)) fseek(fp, pos, 0);
  277. #else
  278.   fseek(fp,pos,0);
  279. #endif
  280.   
  281.   bytes = fread(ub->buf, 1, len, fp);
  282.   
  283. #ifdef VMS /* some stupid VMS-bug in fread */
  284.   while (!bytes && errno==65535 && rtime) {
  285.     rtime--;
  286.     bytes=fread(ub->buf,1, len, fp);
  287.   }
  288. #endif
  289.   
  290.   server_reply(from,ub,bytes,0);
  291. }
  292.  
  293. /****************************************************************************
  294.  * The two UDP socket initialization routines.  One for running alone.
  295.  * The other for running under inetd.
  296.  ****************************************************************************/
  297.  
  298. void init_network PROTO1(int, port)
  299. {
  300.   int i;
  301.   
  302.   /* init throughput control */
  303.   if(maxthcallowed) {
  304.     for(i = 0; i<THCCOUNT; thc[i++]=0);
  305.     time(&thcbase);
  306.   }
  307.   
  308.   myport = port;
  309.   
  310.   if((myfd = _x_udp(&myport)) == -1) {
  311.     perror("socket open");
  312.     exit(1);
  313.   }
  314.   
  315.   if(dbug) {
  316.     fprintf(stderr,"listening on port %d\n",myport);
  317.     fflush(stderr);
  318.   }
  319.   
  320.   signal(SIGALRM,server_interrupt);
  321. }
  322.  
  323. void init_inetd PROTO0((void))
  324. {
  325.   myfd = dup(0);
  326.   
  327.   signal(SIGALRM,server_interrupt);
  328. }
  329.